#include"HEMUMem.h"

extern HEMUIRFTb func_tb;
extern HEMUIRFInsTb func_inst_tb;
extern HEMUIRGloTb glo_tb;
extern HEMUStack stack;
extern HEMUGMem gmem;


/*
 * return byte size of HEMUIRBtype
 */
size_t get_bsize(HEMUIRBtype tp) {
	size_t bsize;
	switch (tp)
	{
	case HEMUIRBtype::I32:
		bsize = sizeof(int32_t);
		break;
	case HEMUIRBtype::I8:
		bsize = sizeof(int8_t);
		break;
	case HEMUIRBtype::FLOAT:
		bsize = sizeof(float);
		break;
	case HEMUIRBtype::DOUBLE:
		bsize = sizeof(double);
		break;
	case HEMUIRBtype::POINTER:
		bsize = sizeof(char*);
		break;
	default:
		bsize = 0;
		break;
	}
	return bsize;

}



/*
 * return byte size of HEMUIRType
 */
size_t get_size(HEMUIRType tp) {
	return tp.length * get_bsize(tp.base_type);
}



/*
 * stack mem alloc
 * return stack top
 * aligned by align
 */
char* HEMUStack::salloc(HEMUIRType tp, size_t align) {
	size_t size = get_size(tp);
	top = top - ((size_t)(top) % align);
	top = top - size;
	assert(top >= (char*)(mem));
	return top;
}


/*
 * free stack mem by old top
 */
bool HEMUStack::free(char* otop) {
	top = otop;
	return true;
}

/*
 * store via HEMUIRVar
 * return type byte size
 */
size_t hstore(char* addr, const HEMUIRVar& var) {
	switch (var.btype)
	{
	case HEMUIRBtype::I32:
		*((int32_t*)(addr)) = var.val.i32_val;
		break;
	case HEMUIRBtype::I8:
		*((int8_t*)(addr)) = var.val.i8_val;
		break;
	case HEMUIRBtype::FLOAT:
		*((float*)(addr)) = var.val.float_val;
		break;
	case HEMUIRBtype::DOUBLE:
		*((double*)(addr)) = var.val.double_val;
		break;
	case HEMUIRBtype::POINTER:
		*((char**)(addr)) = var.val.ptr_val;
		break;
	default:
		return 0;
		break;
	}
	return get_bsize(var.btype);
}


/*
 * store via vector<HEMUIRVar>
 */
size_t hstore(char* addr, HEMUIRType tp, const std::vector<HEMUIRVar>& vars) {
	size_t size = 0;
	for (size_t idx = 0; idx < tp.length; idx++)
	{
		size += hstore(addr + size, vars.at(idx));
	}
	return size;
}

/*
 * store via bool zero
 */
size_t hstore(char* addr, HEMUIRType tp, bool zero) {
	if (zero) {
		size_t size = 0;
		HEMUIRVar var;
		var.btype = tp.base_type;
		var.val.i64_val = 0;
		for (size_t idx = 0; idx < tp.length; idx++)
		{
			size = size + hstore(addr + size, var);
		}
		return size;
	}
	else
		return 0;
}


/* load var
 * return HEMUIRVar
 */
HEMUIRVar hload(char* addr, HEMUIRBtype tp) {
	HEMUIRVar var;
	var.btype = tp;
	switch (var.btype)
	{
	case HEMUIRBtype::I32:
		var.val.i32_val = *((int32_t*)(addr));
		break;
	case HEMUIRBtype::I8:
		var.val.i8_val = *((int8_t*)(addr));
		break;
	case HEMUIRBtype::FLOAT:
		var.val.float_val = *((float*)(addr));
		break;
	case HEMUIRBtype::DOUBLE:
		var.val.double_val = *((double*)(addr));
		break;
	case HEMUIRBtype::POINTER:
		var.val.ptr_val = *((char**)(addr));
		break;

	default:
		var.val.i64_val = 0;
		break;
	}
	return var;
}

/* determine whether the addr is valid
 */
bool valid_addr(char* addr) {
	return (addr >= (char*)(stack.top) && addr <= (char*)(&stack.mem[MEM_SIZE])) || (addr >= (char*)(gmem.mem) && addr <= (char*)(gmem.top));
}

/*
 * glo mem alloc
 * return otop to use
 * aligned by align
 */
char* HEMUGMem::galloc(HEMUIRType tp, size_t align) {
	size_t size = get_size(tp);
	top = top + ((align - (size_t)(top) % align) % align);
	char* otop = top;
	top = top + size;
	return otop;
}

bool HEMUGMem::free(char* otop) {
	top = otop;
	return true;
}






